package models

import (
	"errors"
	"fmt"
	"gorm.io/gorm/clause"
	"time"
)

// AdminMenu 菜单模型
type AdminMenu struct {
	Id          uint        `json:"id"`
	ParentId    uint        `json:"parent_id"`
	Order       int         `json:"order"`
	Label       string      `json:"label"`
	Router      string      `json:"router"`
	Href        string      `json:"href"`
	Path        string      `json:"path"`
	Key         string      `json:"key"`
	IconLibrary string      `json:"icon_library"`
	Icon        string      `json:"icon"`
	Show        int         `json:"show"`
	Apis        []AdminApi  `json:"apis" gorm:"many2many:admin_menu_api"`
	CreatedAt   time.Time   `json:"-"`
	UpdatedAt   time.Time   `json:"-"`
	Children    interface{} `json:"children" gorm:"-"`
}

// @title 数据校验
func (a *AdminMenu) validation() error {
	if a.Label == "" {
		return errors.New("名称不能为空")
	}

	if a.Key == "" {
		return errors.New("标识符不能为空")
	}

	var count int64
	Db.Model(AdminMenu{}).Where("`key` = ?", a.Key).Where("id <> ?", a.Id).Count(&count)

	if count > 0 {
		return errors.New("标识符重复")
	}

	return nil
}

// @title 添加
func (a *AdminMenu) Store() error {
	check := a.validation()
	if check != nil {
		return check
	}

	a.Id = 0

	res := Db.Model(a).Omit(clause.Associations).Create(&a)

	fmt.Println(a.Id)

	a.handleAssociations()

	return res.Error
}

// @title 修改
func (a *AdminMenu) Update() error {
	check := a.validation()
	if check != nil {
		return check
	}

	if parentInChildren(a.Id, a.ParentId) {
		return errors.New("父级菜单不能是当前菜单的子菜单")
	}

	a.handleAssociations()

	return Db.Model(a).Where("id = ?", a.Id).Omit(clause.Associations).Save(a).Error
}

// @title 查询父菜单是否是当前菜单的子菜单
// @todo 这里在递归查mysql, 按理来说应该只查一次, 懒得想了
func parentInChildren(id, parentId uint) bool {
	var menu AdminMenu
	Db.Model(AdminMenu{}).Where("id = ?", parentId).First(&menu)

	if menu.ParentId == id {
		return true
	}

	if menu.ParentId == 0 {
		return false
	} else {
		return parentInChildren(id, menu.ParentId)
	}
}

// @title 处理关联关系
func (a *AdminMenu) handleAssociations() {
	var menuApi []map[string]interface{}

	for _, item := range a.Apis {
		menuApi = append(menuApi, map[string]interface{}{
			"admin_menu_id": a.Id,
			"admin_api_id":  item.Id,
		})
	}

	Db.Table("admin_menu_api").Where("admin_menu_id = ?", a.Id).Delete(nil)

	if len(menuApi) > 0 {
		Db.Table("admin_menu_api").Create(menuApi)
	}
}

// @title 获取树状列表
func (a *AdminMenu) TreeList() ([]AdminMenu, error) {
	list := []AdminMenu{}
	res := Db.Model(a).Preload("Apis").Order("`order` desc").Find(&list)

	if res.Error != nil {
		return nil, res.Error
	}

	return a.treeHandler(list, 0), nil
}

// @title 处理成树形数据
func (a *AdminMenu) treeHandler(data []AdminMenu, parentId uint) []AdminMenu {
	var list []AdminMenu
	for _, val := range data {
		if val.ParentId == parentId {
			val.Children = a.treeHandler(data, val.Id)
			list = append(list, val)
		}
	}
	return list
}

// @title 删除
func (a *AdminMenu) Delete() error {
	if a.Id == 0 {
		return errors.New("id不可为空")
	}

	// 查询子菜单
	var subs []AdminMenu
	Db.Where("parent_id = ?", a.Id).Find(&subs)

	if len(subs) > 0 {
		// 递归删除子菜单
		for _, item := range subs {
			item.Delete()
		}
	}

	// 删除当前菜单及关联关系
	Db.Table("admin_menu_api").Where("admin_menu_id = ?", a.Id).Delete(nil)
	res := Db.Where("id = ?", a.Id).Delete(AdminMenu{})

	return res.Error
}
